<template>
  <div>
    <n-card style="margin-bottom: 5px;height: 100px;">
      <n-spin :show="resourceLoading">
        <n-form inline>
          <n-grid :x-gap="10">
            <n-grid-item span="4">
              <n-form-item label="资源选择" path="sdResourceId">
                <n-select v-model:value="text2ImgPrompt.resourceId" :options="resourceOption"
                          @update:value="resourceSelect">
                </n-select>
                <!--                <n-button @click="refreshCache" style="margin-left:5px; ">-->
                <!--                  <template #icon>-->
                <!--                    <n-icon>-->
                <!--                      <SyncCircleOutline/>-->
                <!--                    </n-icon>-->
                <!--                  </template>-->
                <!--                </n-button>-->
              </n-form-item>
            </n-grid-item>

            <n-grid-item span="5">
              <n-form-item label="CHECKPOINT" path="defaultModel">
                <n-select
                    v-model:value="text2ImgPrompt.base_model_name"
                    :options="modelOptions"
                    style="width: 100%"
                />
              </n-form-item>
            </n-grid-item>

            <n-grid-item :span="5">
              <n-form-item label="Refiner" path="defaultVae">
                <n-select
                  :clearable="true"
                    :options="modelOptions"
                    v-model:value="text2ImgPrompt.refiner_model_name"
                />
              </n-form-item>
            </n-grid-item>

            <n-grid-item :span="5">
              <n-form-item label="Refiner Switch At" path="defaultVae" v-if="text2ImgPrompt.refiner_model_name && text2ImgPrompt.refiner_model_name.length>0">
                <n-slider v-model:value="text2ImgPrompt.refiner_switch" :step="0.01" :min="0" :max="1" />
              </n-form-item>
            </n-grid-item>
            <n-grid-item :span="5">
              <n-form-item label="尺寸">
                <n-select
                    :options="aspect_ratios"
                    v-model:value="text2ImgPrompt.aspect_ratios_selection"
                    label-field="size"
                    value-field="size"
                    :render-label="renderLabel"
                />
              </n-form-item>
            </n-grid-item>
          </n-grid>
        </n-form>
      </n-spin>
    </n-card>
    <n-grid :x-gap="5">
      <n-grid-item span="14">
        <n-card style="height: 460px;">
          <n-space justify="center">
            <n-el v-if="selectedPic != '' && selectedPic != null  "
                  style="background: var(--hover-color);margin-top:10px">
              <n-space style="padding: 10px;">
                <n-image
                    :height="300"
                    :src=fileFunction.getViewFilePathByUserFileId(selectedPic)
                />
              </n-space>
            </n-el>
          </n-space>
          <n-space style="margin-top:20px">
            <n-scrollbar x-scrollable style="max-height: 80px">
              <div style="white-space: nowrap;">
                <n-image v-for="pic in picList"
                         preview-disabled
                         :lazy="true"
                         :width="70"
                         size="small"
                         @click="selectedPic = pic"
                         :class="{ 'selected': pic == selectedPic }"
                         style="margin-left: 10px;"
                         :src=fileFunction.getViewFilePathByUserFileId(pic)
                />
              </div>
            </n-scrollbar>
          </n-space>
        </n-card>
        <n-card style="margin-top: 5px;">
          <n-form :label-width="100" :model="text2ImgPrompt" :rules="rules" ref="formRef">
            <n-form-item-gi path="prompt" label="正向提示词">
              <n-input v-model:value="text2ImgPrompt.prompt" type="textarea" style="height: 80px"/>
              <n-button type="primary" style="height: 80px;width: 80px;margin-left:5px;" @click="generateImg"
                        :loading="buttonLoading">
                生成
              </n-button>
            </n-form-item-gi>
          </n-form>
<!--          <n-checkbox v-model:checked="input_image">-->
<!--            Input Image-->
<!--          </n-checkbox>-->
        </n-card>

        <n-card v-if="input_image" style="margin-top: 2px">
          <n-tabs type="line" animated>
            <n-tab-pane name="UpscaleOrVar" tab="放大或变化">
              Wonderwall
            </n-tab-pane>
            <n-tab-pane name="Image Prompt" tab="图片提示">
              Hey Jude
            </n-tab-pane>
            <n-tab-pane name="Inpaint or OutPaint" tab="重绘">
              七里香
            </n-tab-pane>
            <n-tab-pane name="Describe" tab="反推关键词">
              <Describe :resourceId="text2ImgPrompt.resourceId" :descriptionFunction="onDescribeImage"></Describe>
            </n-tab-pane>
          </n-tabs>
        </n-card>
      </n-grid-item>
      <n-grid-item span="10">
        <n-card :content-style="{padding: '10px 10px 10px 10px'}">
          <n-form :rules="rules" size="small" :model="text2ImgPrompt" ref="formRef2" >
            <n-grid :x-gap="5">
              <n-grid-item :span="15">
                <n-form-item label="出图模式" path="performance_selection">
                  <n-radio-group v-model:value="text2ImgPrompt.performance_selection" name="performance_selection">
                    <n-space>
                      <n-radio value="Speed">
                        普通模式
                      </n-radio>
                      <n-radio value="Quality">
                        质量模式
                      </n-radio>
                      <n-radio value="Extreme Speed">
                        急速模式
                      </n-radio>
                      <n-radio value="Lightning">
                        闪电模式
                      </n-radio>
                    </n-space>
                  </n-radio-group>
                </n-form-item>
              </n-grid-item>

              <n-grid-item :span="9">
                <n-form-item label="种子(-1随机)" path="image_seed">
                  <n-input-group>
                    <n-input-number v-model:value="text2ImgPrompt.image_seed" :min=-1></n-input-number>
                  </n-input-group>
                </n-form-item>
              </n-grid-item>
            </n-grid>
            <n-grid :cols="24" :x-gap="5">
              <n-form-item-gi :span="8" label="生成数量" path="image_number">
                <n-input-number v-model:value="text2ImgPrompt.image_number" :max="4" :min="1">
                </n-input-number>
              </n-form-item-gi>
              <n-form-item-gi :span="8" label="Guidance Scale" path="guidance_scale">
                <n-input-number v-model:value="text2ImgPrompt.guidance_scale" :min="0" :max="30">
                </n-input-number>
              </n-form-item-gi>
              <n-form-item-gi :span="8" label="Sampling Sharpness" path="sharpness">
                <n-input-number v-model:value="text2ImgPrompt.sharpness" :min="0" :max="30">
                </n-input-number>
              </n-form-item-gi>
            </n-grid>
            <n-form-item path="negativePrompt" label="反向提示词" :show-label="false">
              <n-input v-model:value="text2ImgPrompt.negative_prompt" placeholder="输入反向提示词"/>
            </n-form-item>
            <n-tabs
                class="card-tabs"
                default-value="style"
                size="small"
                animated
                pane-wrapper-style="margin: 0 -4px"
                pane-style="padding-left: 4px; padding-right: 4px; box-sizing: border-box;"
            >
              <n-tab-pane name="style" tab="风格" display-directive="show">
<!--                <n-input style="margin-bottom: 5px;"  v-model:value="styleQuery" placeholder="请输入风格名称" clearable></n-input>-->
                <n-scrollbar style="max-height: 400px">
                  <n-grid :x-gap="2" :y-gap="2">
                    <n-grid-item :span="4" v-for="style in stylesOption">
                      <n-card :content-style="{padding:'2px 2px 2px 2px'}" @click="styleClick(style)">
                        <template #cover>
<!--                          <img :src="'/src/assets/fooocus/'+style.image" >-->
                          <img :src="'/assets/fooocus/'+style.image" >
                        </template>
                        <n-grid>
                          <n-grid-item :span="6">
                            <n-checkbox size="small" v-model:checked="style.isCheck"></n-checkbox>
                          </n-grid-item>
                          <n-grid-item :span="18">
                            <n-ellipsis :line-clamp="1">
                              {{style.label}}
                            </n-ellipsis>
                          </n-grid-item>
                        </n-grid>
                      </n-card>
                    </n-grid-item>
                  </n-grid>

<!--                  <n-checkbox-group v-model:value="text2ImgPrompt.style_selections">-->
<!--                    <n-grid :y-gap="8" :cols="3">-->
<!--                      <n-gi v-for="style in stylesOption">-->
<!--                        <n-checkbox :value="style.label" :label="style.translation"/>-->
<!--                      </n-gi>-->
<!--                    </n-grid>-->
<!--                  </n-checkbox-group>-->
                </n-scrollbar>
              </n-tab-pane>
              <n-tab-pane name="lora" tab="Lora" display-directive="show">
                <n-grid :x-gap="6" v-for="(lora,index) in text2ImgPrompt.loras">
                  <n-grid-item :span="12">
                    <n-form-item-gi :label="`loRA ` + (index + 1)">
                      <n-select :options="loraOptions" v-model:value="lora.model_name" clearable>
                      </n-select>
                    </n-form-item-gi>
                  </n-grid-item>

                  <n-grid-item :span="12">
                    <n-form-item-gi label="权重">
                      <n-input-number :min="-2" :max="2" :step="0.01" v-model:value="lora.weight"></n-input-number>
                    </n-form-item-gi>
                  </n-grid-item>
                </n-grid>
              </n-tab-pane>
            </n-tabs>


          </n-form>
        </n-card>
      </n-grid-item>
    </n-grid>
  </div>
</template>

<script setup lang="ts">
import {onMounted, reactive, ref} from 'vue';
import {useMessage} from 'naive-ui';
// @ts-ignore
import fileFunction from '@/libs/globalFunction/file.js'
import {fooocusControllerApi} from "@/api/paint/fooocusController.api";
import {resourceController} from "@/api/resource/resourceController.api";
import {sdControllerApi} from "@/api/sd/sdController.api";
import Describe from '@/views/pages/aiart/fooocus/component/Describe.vue'
import {fooocusDict} from "@/dictionary/fooocusDict";
import fooocusZh from '@/views/pages/aiart/fooocus/component/zh.json'



const {aspect_ratios} = fooocusDict()

const props = defineProps({
  mode: {
    type: String,
    default: 'image'
  }
})

const styleQuery = ref(null)
const checked = ref(false)
const formRef: any = ref(null);
const formRef2  = ref(null)
const message = useMessage();
const resourceLoading = ref(false)
const modelOptions = ref([])
const refinerOptions = ref([])
const loraOptions = ref([])
const resourceOption = ref([])
// const resourceInfo = reactive({
//   base_model_name: '',
//   refiner_model_name: '',
//   loras: [{
//     model_name: "sd_xl_offset_example-lora_1.0.safetensors"
//   }],
//   resourceId: ''
// })
const stylesOption = ref([])

const input_image = ref(false)



const resourceSelect = (value: string) => {
  text2ImgPrompt.resourceId = value
  getResourceConfig(value)
}

// 获取SD资源详情
const getResourceConfig = (resouceId: string) => {
  resourceLoading.value = true
  fooocusControllerApi.getFooocusModelInfo(resouceId).then(res => {
    if (res.code === 200) {
      modelOptions.value = []
      res.data.model_filenames.forEach((item: any) => {
        // @ts-ignore
        modelOptions.value.push({
          label: item,
          value: item
        })
      })
      if (res.data.model_filenames.length > 0) {
        text2ImgPrompt.base_model_name = res.data.model_filenames[0]
      }
      refinerOptions.value = []
      res.data.refiner_filenames?.forEach((item: any) => {
        // @ts-ignore
        refinerOptions.value.push({
          label: item,
          value: item
        })
      })
      if (res.data.refiner_model_name?.length > 0) {
        resourceInfo.refiner_model_name = res.data.refiner_model_name[0]
      }
      loraOptions.value = []
      res.data.lora_filenames?.forEach((item: any) => {
        // @ts-ignore
        loraOptions.value.push({
          label: item,
          value: item
        })
      })

      // stylesOption.value = []
      // res.data.styles?.forEach((item: any) => {
      //   // @ts-ignore
      //   const styleItem = {
      //     label: item,
      //     translation: item
      //   }
      //   stylesOption.value.push(styleItem)
      // })
      initStyle(res.data.styles)
    } else {
      window.$message.error(res.msg)
    }
  }).finally(() => {
    resourceLoading.value = false
  })
}

const initStyle = (styles:[])=>{
  stylesOption.value = []
  const stylesCheck = ref([])
  styles.forEach((item:any)=>{
    if (text2ImgPrompt.style_selections.includes(item)) {
      stylesCheck.value.push(item)
      stylesOption.value.push({
        label: fooocusZh[item]?fooocusZh[item]:item,
        value: item,
        image: item.toLowerCase().replaceAll(' ','_')+ '.jpg',
        isCheck: true
      })
    }
  })
  styles.forEach((item:any)=>{
    if (!stylesCheck.value.includes(item)) {
      stylesOption.value.push({
        label: fooocusZh[item]?fooocusZh[item]:item,
        value: item,
        image: item.toLowerCase().replaceAll(' ','_')+ '.jpg',
        isCheck: false
      })
    }
  })
}

const refreshCache = () => {
  resourceLoading.value = true
  sdControllerApi.refreshSDOption(text2ImgPrompt.resourceId).then(res => {
    resourceLoading.value = false
    if (res.code === 200) {
      window.$message.success('刷新成功!')
    } else {
      window.$message.error(res.msg);
    }
  }).finally(() => {
    resourceLoading.value = false
  })
}

/***
 * 获取绘画资源
 */
const getResourceInfo = () => {
  resourceController.getSDResource('Fooocus').then(res => {
    if (res.code === 200) {
      res.data.forEach((item: any) => {
        // @ts-ignore
        resourceOption.value.push({
          label: item.resourceName,
          value: item.id
        })
      })
      if (res.data.length > 0) {
        text2ImgPrompt.resourceId = res.data[0].id
        getResourceConfig(res.data[0].id)
      }
    } else {
      window.$message.error(res.msg);
    }
  }).catch((e) => {
    window.$message.error("获取资源失败")
  })
}

onMounted(() => {
  getResourceInfo()
});

// 初始化数据
const text2ImgPrompt: Fooocus.Text2ImgModel = reactive({
  resourceId:'',
  prompt: '',
  negative_prompt: '',
  style_selections: [
    "Fooocus V2",
    "Fooocus Enhance",
    "Fooocus Sharp"
  ],
  performance_selection: 'Extreme Speed',
  aspect_ratios_selection: '1152*896',
  image_number: 1,
  image_seed: -1,
  sharpness: 2,
  guidance_scale: 4,
  base_model_name: 'animaPencilXL_v100.safetensors',
  refiner_model_name: '',
  refiner_switch: 0.5,
  loras: [{
    model_name: "sd_xl_offset_example-lora_1.0.safetensors",
    weight: 0.1
  }, {
    model_name: "",
    weight: 1
  }, {
    model_name: "",
    weight: 1
  }, {
    model_name: "",
    weight: 1
  }],
  advanced_params: {
    adaptive_cfg: 7,
    adm_scaler_end: 0.3,
    adm_scaler_negative: 0.8,
    adm_scaler_positive: 1.5,
    canny_high_threshold: 128,
    canny_low_threshold: 64,
    controlnet_softness: 0.25,
    debugging_cn_preprocessor: false,
    debugging_inpaint_preprocessor: false,
    disable_intermediate_results: false,
    disable_preview: false,
    disable_seed_increment: false,
    freeu_b1: 1.01,
    freeu_b2: 1.02,
    freeu_enabled: false,
    freeu_s1: 0.99,
    freeu_s2: 0.95,
    inpaint_disable_initial_latent: false,
    inpaint_engine: "v1",
    inpaint_erode_or_dilate: 0,
    inpaint_mask_upload_checkbox: false,
    inpaint_respective_field: 1,
    inpaint_strength: 1,
    invert_mask_checkbox: false,
    mixing_image_prompt_and_inpaint: false,
    mixing_image_prompt_and_vary_upscale: false,
    overwrite_height: -1,
    overwrite_step: -1,
    overwrite_switch: -1,
    overwrite_upscale_strength: -1,
    overwrite_vary_strength: -1,
    overwrite_width: -1,
    refiner_swap_method: "joint",
    sampler_name: "dpmpp_2m_sde_gpu",
    scheduler_name: "karras",
    skipping_cn_preprocessor: false
  },
  require_base64: true,
  async_process: false,
});


const drawerWidth = ref(0)

const picList = ref([])
const selectedPic = ref(null)
const buttonLoading = ref(false)

const rules = {
  prompt: {
    required: true,
    message: '请输入提示词',
    trigger: 'submit',
  },
  image_seed:{
    required: true,
    type: 'number',
    message: '请输入数字',
    trigger: 'submit',
  },
  performance_selection:{
    required: true,
    message: '请选择出图模式',
    trigger: 'submit'
  },
  sharpness:{
    required: true,
    type: 'number',
    message: '请输入数字',
    trigger: 'submit'
  },
  guidance_scale:{
    required: true,
    type: 'number',
    message: '请输入数字',
    trigger: 'submit'
  },
  image_number: {
    required: true,
    type: 'number',
    message: '请输入数字',
    trigger: 'submit'
  }

};

/**初始化事件**/
onMounted(() => {
  // 设置当前drawerWidth 宽度
  drawerWidth.value = window.innerWidth - 300;
  window.addEventListener('resize', handleResize);
})

// 窗口宽度变化
const handleResize = () => {
  drawerWidth.value = window.innerWidth - 300;
}

/**提交任务**/
const generateImg = async () => {
  Promise.all([
    validateForm(formRef),
      validateForm(formRef2)
  ]).then(async (results) => {
    if (results.every(item => item)) {
      buttonLoading.value = true;
      let copyText2ImgPrompt = {...text2ImgPrompt};
      copyText2ImgPrompt.loras = copyText2ImgPrompt.loras.filter(item => item.model_name !== "" && item.model_name!=null)
      // 更新prompt
      await fooocusControllerApi.generateText2ImgAndCheck(copyText2ImgPrompt, 5 * 60 * 1000).then(res => {
        const images = res.userFileId.split(',')
        for (let i = 0; i < images.length; i++) {
          picList.value.push(images[i])
        }
        selectedPic.value = images[0]
      }).finally(() => {
        buttonLoading.value = false;
      })
    }
  })

}

const renderLabel = (option: any) => {
  return option.size + ' 【比例:' + option.ratio + '】'
}

const onDescribeImage = (describeObj:string) =>{
  text2ImgPrompt.prompt = describeObj
}



const validateForm = (fr:any) =>{
  return new Promise((resolve) => {
    fr.value?.validate((errors) => {
      console.log(errors)
      if(!errors){
        resolve(true)
      }else {
        resolve(false)
      }
    });
  });
}



const getConfig = async () => {
  return Promise.all([
      validateForm(formRef2)
  ]).then(async (results) => {
    const allValid = results.every((valid) => valid)
    console.log(allValid)
    if (allValid) {
      return {...text2ImgPrompt}
    }else {
      return null
    }
  })
}

const loadConfig = (paintConfig: string, selectedResource: string) => {
  if (paintConfig != null && paintConfig.length > 0) {
    const config = JSON.parse(paintConfig)
    text2ImgPrompt.resourceId = config.resourceId
    text2ImgPrompt.prompt = config.prompt
    text2ImgPrompt.negative_prompt = config.negative_prompt
    text2ImgPrompt.style_selections = config.style_selections
    text2ImgPrompt.performance_selection = config.performance_selection
    text2ImgPrompt.aspect_ratios_selection = config.aspect_ratios_selection
    text2ImgPrompt.image_number = config.image_number
    text2ImgPrompt.image_seed = config.image_seed
    text2ImgPrompt.sharpness = config.sharpness
    text2ImgPrompt.guidance_scale = config.guidance_scale
    text2ImgPrompt.base_model_name = config.base_model_name
    text2ImgPrompt.refiner_model_name = config.refiner_model_name
    text2ImgPrompt.refiner_switch = config.refiner_switch
    text2ImgPrompt.loras = config.loras
    text2ImgPrompt.advanced_params = config.advanced_params
  }
}

const styleClick = (style:any) =>{
  style.isCheck = !style.isCheck
  if (style.isCheck) {
    text2ImgPrompt.style_selections.push(style.value)
  }else {
    text2ImgPrompt.style_selections = text2ImgPrompt.style_selections.filter(item => item !== style.value);
  }
  console.log(text2ImgPrompt.style_selections)
  const styles = []
  stylesOption.value.forEach((item:any)=>{
    styles.push(item.value)
  })
  initStyle(styles)
}

defineExpose({
  getConfig, loadConfig
})


</script>


<style>
.selected {
  border: 3px solid #8250df;
}
</style>
